﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using Iot.Shared.Helper;

namespace Iot.RealTimeData.WPF.Prism.ValueConverter;

/// <summary>
///     枚举与字符串转换器，实现 IValueConverter 接口，用于在 XAML 绑定中转换枚举值和对应的显示名称
/// </summary>
public class EnumToStrConverter : IValueConverter
{
    /// <summary>
    ///     将值转换为目标类型，支持单个枚举值、枚举数组和其他类型的转换
    /// </summary>
    /// <param name="value">要转换的值</param>
    /// <param name="targetType">目标类型</param>
    /// <param name="parameter">转换参数</param>
    /// <param name="culture">区域性信息</param>
    /// <returns>转换后的值</returns>
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        // 使用switch表达式根据值的类型返回不同的结果
        return value switch
        {
            // 当值为枚举类型时，调用GetDisplayName方法获取显示名称
            Enum onValue => onValue.GetDisplayName(),
            // 当值为可枚举集合类型时，调用ConvertArray方法转换集合
            IEnumerable enumerable => ConvertArray(enumerable, value),
            // 其他类型直接返回原值
            _ => value
        };
    }

    /// <summary>
    ///     将值转换回源类型，主要用于双向绑定
    /// </summary>
    /// <param name="value">要转换的值</param>
    /// <param name="targetType">目标类型</param>
    /// <param name="parameter">转换参数</param>
    /// <param name="culture">区域性信息</param>
    /// <returns>转换后的值</returns>
    public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        // 使用三元运算符检查value是否为null
        // 如果value为null，则直接返回value
        // 如果value不为null，则调用ToEnum方法将value转换为targetType类型的枚举
        return ToEnum(value, targetType);
    }

    /// <summary>
    ///     将输入值转换为指定的枚举类型
    /// </summary>
    /// <param name="value">要转换的值</param>
    /// <param name="type">目标枚举类型</param>
    /// <returns>转换后的枚举值</returns>
    private static object? ToEnum(object? value, Type type)
    {
        // 尝试获取基础枚举类型，如果失败则直接返回原始值
        if (value is null || !GetUnderlyingEnumType(type, out var enumType)) return value;
        // 使用 switch 表达式根据 value 的类型进行不同的处理
        return value switch
        {
            // 当 value 是字符串类型时，尝试解析为枚举值
            // 如果解析失败，则调用 GetEnum 方法进行进一步处理
            string str => Enum.TryParse(enumType, str, true, out var enumValue)
                ? enumValue
                : enumType.DisplayNameToEnum(str),

            // 当 value 是整数类型时，检查该值是否在枚举中定义
            // 如果已定义，则转换为对应的枚举对象，否则返回原始值
            int or long or short or byte or uint or ulong or ushort or sbyte => enumType.IsDefined(value)
                ? Enum.ToObject(enumType, value)
                : value,

            // 当 value 是可枚举集合时，对集合中的每个元素递归调用 ToEnum 方法
            IEnumerable enumerable => from object? item in enumerable select ToEnum(item, enumType),

            // 其他类型直接返回原始值
            _ => value
        };
    }

    /// <summary>
    ///     转换枚举数组或可枚举集合为字符串数组
    /// </summary>
    /// <param name="enumerable">要转换的可枚举集合</param>
    /// <param name="value">原始值，用于转换失败时返回</param>
    /// <returns>转换后的字符串数组或原始值</returns>
    private static object? ConvertArray(IEnumerable enumerable, object? value)
    {
        // 检查输入的可枚举对象是否是枚举数组
        if (enumerable is Enum[] enumArray)
        {
            // 如果是枚举数组，则使用Array.ConvertAll方法将所有枚举值转换为显示名称
            return Array.ConvertAll(enumArray, EnumHelper.GetDisplayName);
        }

        // 创建一个新的字符串列表用于存储结果
        var data = new List<string>();
        // 遍历输入的可枚举对象中的每个元素
        foreach (var item in enumerable)
        {
            // 使用switch表达式处理不同类型的元素
            switch (item)
            {
                // 如果元素是枚举类型，获取其显示名称并添加到列表中
                case Enum enumItem:
                    data.Add(enumItem.GetDisplayName());
                    break;
                // 如果元素是null，添加空字符串到列表中（或使用null，根据需求）
                case null:
                    data.Add(string.Empty); // 或使用 null，根据需求
                    break;
                // 如果元素既不是枚举类型也不是null，直接返回原始值
                default:
                    return value;
            }
        }

        // 将列表转换为数组并返回
        return data.ToArray();
    }

    /// <summary>
    ///     获取底层的枚举类型，支持可空枚举、枚举数组和泛型集合
    /// </summary>
    /// <param name="type">要检查的类型</param>
    /// <param name="enumType">输出的枚举类型</param>
    /// <returns>如果类型是枚举或包含枚举则返回 true，否则返回 false</returns>
    private static bool GetUnderlyingEnumType(Type type, [MaybeNullWhen(false)] out Type enumType)
    {
        // 检查类型是否为枚举类型
        if (type.IsEnum)
        {
            enumType = type;
            return true;
        }

        // 检查类型是否为可空枚举类型（Nullable<>）
        if (type.IsGenericType &&
            type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
            type.GenericTypeArguments[0].IsEnum)
        {
            enumType = type.GenericTypeArguments[0];
            return true;
        }

        // 检查类型是否为枚举数组类型
        if (type.IsArray && type.GetElementType() is { IsEnum: true })
        {
            enumType = type.GetElementType();
            return enumType is not null;
        }

        // 检查类型是否为泛型类型或接口，并实现IEnumerable<>
        if (type.IsGenericType || type.IsInterface)
        {
            // 获取类型及其接口中第一个实现IEnumerable<>的类型
            var iEnumerableInterface = type.GetInterfaces()
                .Append(type)
                .FirstOrDefault(static i => i.IsGenericType &&
                                            i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
            if (iEnumerableInterface != null)
            {
                // 获取集合元素的类型
                var elementType = iEnumerableInterface.GenericTypeArguments[0];
                // 检查元素类型是否为枚举
                if (elementType.IsEnum)
                {
                    enumType = elementType;
                    return true;
                }
            }
        }


        // 如果以上条件都不满足，设置enumType为null并返回false
        enumType = null;
        return false;
    }
}